﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Furion.DatabaseAccessor;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using YBlog.Application.Contracts;
using YBlog.Application.Contracts.System.Menus;
using YBlog.Application.Contracts.System.Routes;
using YBlog.Core.System;

namespace YBlog.Application.System
{
    /// <summary>
    /// 菜单
    /// </summary>
    [ApiDescriptionSettings("System")]
    public class MenuService : IMenuService, IBaseService
    {
        #region 缓存Key
        public readonly string MenuKey = "MenuService.GetListAllAsync";
        #endregion
        private IRepository<Menu> _menuRepository;
        private readonly IRepository<Route> _routeRepository;
        private readonly IMemoryCacheService _memoryCache;
        private readonly IRouteService _routeService;
        private readonly IRepository _repository;

        public MenuService(IRepository repository,IRepository<Menu> menuRepository, IRepository<Route> routeRepository, IMemoryCacheService memoryCache,IRouteService routeService)
        {
            _repository = repository;
            _menuRepository = menuRepository;
            _routeRepository = routeRepository;
            _memoryCache = memoryCache;
            _routeService = routeService;
        }
        /// <summary>
        /// 创建菜单
        /// </summary>
        /// <param name="createUpdateDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        public async Task<object> CreateAsync(MenuCreateUpdateDto createUpdateDto)
        {
            var menu = new Menu();
            var config = new TypeAdapterConfig();
            config.ForType<MenuCreateUpdateDto, Menu>().Ignore(p => p.Id);
            createUpdateDto.Adapt(menu, config);
            var route = new Route
            {
                Name = createUpdateDto.RouteName,
                Path = createUpdateDto.RoutePath,
                Redirect = createUpdateDto.RouteRedirect,
                Component = createUpdateDto.RouteComponent,
            };
            menu.RouteId = route.Id;

            await _memoryCache.RemoveAsync(MenuKey);
            return new { menu = (await _menuRepository.InsertNowAsync(menu)).Entity, route = (await _routeRepository.InsertNowAsync(route)).Entity };
        }
        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="createUpdateDto"></param>
        /// <returns></returns>
        [UnitOfWork]
        public async Task<object> UpdateAsync(MenuCreateUpdateDto createUpdateDto)
        {
            var menu = createUpdateDto.Adapt<Menu>();
            var route = new Route
            {
                Id = createUpdateDto.RouteId ?? Guid.NewGuid().ToString(),
                Name = createUpdateDto.RouteName,
                Path = createUpdateDto.RoutePath,
                Redirect = createUpdateDto.RouteRedirect,
                Component = createUpdateDto.RouteComponent,
            };
            menu.RouteId = route.Id;
            await _memoryCache.RemoveAsync(MenuKey);
            return new 
            {
                menu = (await _menuRepository.UpdateNowAsync(menu)).Entity, 
                route = (await _routeRepository.UpdateNowAsync(route)).Entity,
        };
        }
        /// <summary>
        /// 删除菜单
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteAsync(string id)
        {
            await _menuRepository.FakeDeleteNowAsync(id);
            await _memoryCache.RemoveAsync(MenuKey);
        }
        /// <summary>
        /// 获取全部菜单
        /// </summary>
        /// <returns></returns>
        [ApiDescriptionSettings(Name = "List")]
        public async Task<List<MenuDto>> GetListAsync(MenuSearchDto searchDto)
        {
            var query = from m in GetAllAsync().Result
                        select m;
            return await Task.FromResult(query.ToList());
        }
        /// <summary>
        /// 根据父Id获取子菜单
        /// </summary>
        /// <returns></returns>
        public async Task<List<MenuDto>> GetChildrenAsync(string parentId)
        {
            if (parentId == null)
                return new List<MenuDto>();
            var allList = await GetAllAsync();
            return await Task.FromResult(allList.FindAll(m=>m.ParentId == parentId));
        }
        /// <summary>
        /// 根据ID获取菜单
        /// </summary>
        /// <param name="keyValue"></param>
        /// <returns></returns>
        public async Task<MenuDto> GetAsync(string keyValue)
        {
            if (keyValue == null)
                return null;
            return (await GetAllAsync()).Find(m => m.Id == keyValue);
        }
        [ApiDescriptionSettings(Name = "All")]
        [InitializationCache]
        public async Task<List<MenuDto>> GetAllAsync()
        {
            return await _memoryCache.GetOrCreateAsync(MenuKey, async entry =>
            {
                return await (from m in _menuRepository.AsQueryable()
                              join r in _routeRepository.AsQueryable() on m.RouteId equals r.Id into results
                              from r in results.DefaultIfEmpty()
                              select new MenuDto
                              {
                                  Id = m.Id,
                                  Name = m.Name,
                                  Icon = m.Icon,
                                  Type = m.Type,
                                  HasChild = true,
                                  ParentId = m.ParentId,
                                  RouteId = r.Id,
                                  RouteName = r.Name,
                                  RoutePath = r.Path,
                                  RouteRedirect = r.Redirect,
                                  RouteComponent = r.Component

                              }).AsNoTracking().ToListAsync();
            });
        }
    }
}
